package com.bifrost.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.JSONPath;
import com.alicp.jetcache.anno.CacheType;
import com.alicp.jetcache.anno.Cached;
import com.bifrost.async.CustomerAsync;
import com.bifrost.authorization.manager.impl.RedisTokenManager;
import com.bifrost.common.model.ResultModel;
import com.bifrost.common.util.HttpRequestUtils;
import com.bifrost.constant.BonusPointsSource;
import com.bifrost.constant.BonusPointsUpdatedDetail;
import com.bifrost.constant.BonusPointsUpdatedType;
import com.bifrost.common.constant.SessionConstant;
import com.bifrost.constant.MerchantConfigurationType;
import com.bifrost.entity.*;
import com.bifrost.event.CustomerRegisterEvent;
import com.bifrost.exception.BonusPointsNotEnoughException;
import com.bifrost.exception.KnownRuntimeException;
import com.bifrost.exception.RollbackBonuspointsException;
import com.bifrost.model.AddressModel;
import com.bifrost.model.CustomerModel;
import com.bifrost.repository.*;
import com.bifrost.service.*;
import com.bifrost.util.DateUtils;
import com.bifrost.util.LocalDateUtils;
import com.bifrost.wechat.service.WechatAccountService;
import com.github.binarywang.java.emoji.EmojiConverter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.ApplicationContext;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.time.LocalDate;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author rangjf
 * @date 2017/10/17
 */
@Service("customerService")
@Slf4j
public class CustomerServiceImpl implements CustomerService {

    @Autowired
    CustomerRepository customerRepository;
    @Autowired
    RedisTokenManager redisTokenManager;
    @Autowired
    CustomerAddressRepository customerAddressRepository;
    @Autowired
    CountryAreaRepository countryAreaRepository;
    @Autowired
    MediaService mediaService;
    @Autowired
    BonusPointsHistoryRepository bonusPointsHistoryRepository;
    @Autowired
    WechatAccountService accountService;
    @Autowired
    CustomerCardHistoryRepository customerCardHistoryRepository;

    @Autowired
    ProductSkuService productSkuService;
    @Autowired
    OrderService orderService;
    @Autowired
    BonusPointsService bonusPointsService;
    @Autowired
    CustomerTypeRepository customerTypeRepository;
    @Autowired
    OrderReturnRepository orderReturnRepository;
    @Autowired
    MemberService memberService;
    EmojiConverter emojiConverter = EmojiConverter.getInstance();
    @Autowired
    MerchantStoreRepository merchantStoreRepository;
    @Autowired
    MerchantConfigurationRepository configurationRepository;
    @Autowired
    BonusPointsStoreRepository bonusPointsStoreRepository;
    @Autowired
    CustomerAsync customerAsync;
    @Autowired
    ApplicationContext applicationContext;
    @Autowired
    RedisTemplate<String,String> redis;
    @Autowired
    DailySignInHistoryRepository signInHistoryRepository;

    @Autowired
    CouponService couponService;

    @Autowired
    RedisTemplate<String,String> redisTemplate;
    
    @Override
    public Customer findByCustomerPhone(String phone) {
        return customerRepository.findFirstByCustomerPhone(phone);
    }

    @Override
    public Customer findByOpenId(String openId) {
        return customerRepository.findByOpenId(openId);
    }

    @Override
    public BigInteger getCustomerPoints(Customer customer) {
        BigInteger points = customer.getBonusPoints();
        if (points == null) {
            return BigInteger.ZERO;
        }
        return points;
    }

    @Override
    public Customer saveCustomer(Customer customer) {
        return customerRepository.save(customer);
    }

    @Override
    public Customer findCustomer(Long id) {
        return customerRepository.findOne(id);
    }

    /**
     * 查询会员默认收货地址
     *
     * @param customer
     * @return
     */
    @Override
    public CustomerAddress getCustomerDefaultAddress(Customer customer) {
        Optional<CustomerAddress> address = customer.getCustomerAddresses().stream().filter(customerAddress -> Boolean.TRUE.equals(customerAddress.getIsDefault())).findFirst();
        if (address.isPresent()) {
            return address.get();
        } else {
            return null;
        }
    }

    /**
     * 获取用户所有收货地址
     *
     * @param customer
     * @return
     */
    @Override
    public List<CustomerAddress> getAllAddress(Customer customer) {
        return customerAddressRepository.findAllByCustomer(customer);
    }

    /**
     * 获取用户收货地址详情
     *
     * @param addressId
     * @return
     */
    @Override
    public CustomerAddress getAddrDetail(Long addressId) {
        return customerAddressRepository.findOne(addressId);
    }

    /**
     * 新增收货地址
     *
     * @param customer
     * @param addressModel
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public CustomerAddress addAddr(Customer customer, AddressModel addressModel) {
        //保存地址信息
        CustomerAddress address = new CustomerAddress();
        address.setCustomer(customer);
        address.setAddressState(countryAreaRepository.findOne(addressModel.getState()));
        address.setAddressCity(countryAreaRepository.findOne(addressModel.getCity()));
        address.setAddressDistrict(countryAreaRepository.findOne(addressModel.getDistrict()));
        address.setLastName(addressModel.getReceiver());
        address.setPhonePrimary(addressModel.getPhone());
        address.setAddressStreet(addressModel.getDetail());

       /* if("1".equals(addressModel.getIsDeafult())){
            //原来取消默认地址
            CustomerAddress defaultAddress = getCustomerDefaultAddress(customer);
            if(defaultAddress != null){
                defaultAddress.setIsDefault(Boolean.FALSE);
                customerAddressRepository.save(defaultAddress);
            }
            //设置新添加的为默认地址
            address.setIsDefault(Boolean.TRUE);
        }else{
            //第一次添加地址如果没有设置为默认地址 默认为默认收获地址
            List<CustomerAddress> addresses = getAllAddress(customer);
            if(addresses == null || addresses.isEmpty()){
                address.setIsDefault(Boolean.TRUE);
            }else{
                address.setIsDefault(Boolean.FALSE);
            }
        }*/
        //默认 新添加的地址为默认地址
        CustomerAddress defaultAddress = getCustomerDefaultAddress(customer);
        if (defaultAddress != null) {
            defaultAddress.setIsDefault(Boolean.FALSE);
            customerAddressRepository.save(defaultAddress);
        }
        address.setIsDefault(Boolean.TRUE);
        return customerAddressRepository.save(address);
    }

    /**
     * 更新收货地址
     *
     * @param customer
     * @param addressModel
     * @param addressId
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public CustomerAddress updateAddr(Customer customer, AddressModel addressModel, String addressId) {
        CustomerAddress address = customerAddressRepository.findOne(Long.parseLong(addressId));
        if (address != null) {
            address.setAddressState(countryAreaRepository.findOne(addressModel.getState()));
            address.setAddressCity(countryAreaRepository.findOne(addressModel.getCity()));
            address.setAddressDistrict(countryAreaRepository.findOne(addressModel.getDistrict()));
            address.setLastName(addressModel.getReceiver());
            address.setPhonePrimary(addressModel.getPhone());
            address.setAddressStreet(addressModel.getDetail());
            if ("1".equals(addressModel.getIsDeafult())) {
                CustomerAddress defaultAddress = getCustomerDefaultAddress(customer);
                if (defaultAddress != null) {
                    defaultAddress.setIsDefault(Boolean.FALSE);
                    customerAddressRepository.save(defaultAddress);
                }
                address.setIsDefault(Boolean.TRUE);
            }
            return customerAddressRepository.save(address);
        }
        return null;
    }

    /**
     * 获取用户基本信息
     *
     * @param customerId customerId
     * @return Customer
     */
    @Override
   //@Cached(cacheType = CacheType.REMOTE,name = "customerInfo",expire = 3600,localExpire =1800)
    public CustomerModel getCustomerModel(Long customerId) {
        Customer customer = customerRepository.findOne(customerId);
        if (customer == null) {
            return null;
        }
        CustomerModel model = new CustomerModel();
        model.setCustomerId(customer.getCustomerId());
        model.setName(customer.getCustomerLastname());
        Media media = customer.getMedia();
        model.setBonus(customer.getBonusPoints());
        model.setAvatar(media == null ? null : HttpRequestUtils.getUrl(media.getUrl()));
        return model;

    }

    /**
     * 保存微信基本信息
     *
     * @param customer customer
     * @param request  request
     * @return Customer
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public Customer saveWechatInfo(Customer customer, HttpServletRequest request) {
        Object openId = request.getSession(true).getAttribute(SessionConstant.OPEN_ID);
        Object nickname = request.getSession(true).getAttribute(SessionConstant.NICKNAME);
        nickname = emojiConverter.toUnicode(nickname.toString());//EmojiUtils.filterEmoji(nickname.toString());
        Object sex = request.getSession(true).getAttribute(SessionConstant.SEX);
        Object headImgUrl = request.getSession(true).getAttribute(SessionConstant.HEAD_IMG_URL);
        if (openId != null && !openId.toString().isEmpty()) {
            customer.setOpenId(openId.toString());
            if (customer.getCustomerNickname() == null && nickname != null && !nickname.toString().isEmpty()) {
                customer.setCustomerNickname(nickname.toString());
            }
            if (sex != null && !sex.toString().isEmpty()) {
                customer.setCustomerGender(sex.toString());
            }
            if (customer.getMedia() == null && headImgUrl != null && !headImgUrl.toString().isEmpty()) {
                Media media = new Media();
                media.setAltText(nickname.toString());
                media.setUrl(headImgUrl.toString());
                Media dbMedia = mediaService.save(media);
                customer.setMedia(dbMedia);
            }
        }
        return customerRepository.save(customer);
    }

    /**
     * 返回会员基本信息
     *
     * @param customer customer
     * @return Customer
     */
    @Override
    public CustomerModel getCustomerModelDetail(Customer customer) {
        CustomerModel model = new CustomerModel();
        Media media = customer.getMedia();
        model.setAvatar(media == null ? null : HttpRequestUtils.getUrl(media.getUrl()));
        model.setMediaId(media == null ? null : media.getMediaId());
        model.setBonus(customer.getBonusPoints());
        model.setCustomerId(customer.getCustomerId());
        model.setEmail(customer.getCustomerEmail());
        model.setName(customer.getCustomerLastname());
        model.setNickname(customer.getCustomerNickname());
        model.setPhone(customer.getCustomerPhone());
        model.setSex(customer.getCustomerGender());
        return model;
    }
    @Override
    public CustomerModel getCustomerDetail(Long customerId){
        Customer customer = findCustomer(customerId);
        CustomerModel model = getCustomerModelDetail(customer);
        return model;
    }
    /**
     * 修改会员基本信息
     *
     * @param model    model
     * @param customer customer
     * @return ResultModel
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Customer updateCustomerInfo(Customer customer, CustomerModel model) {
        Long mediaId = model.getMediaId();
        if (mediaId != null) {
            Media dbMedia = customer.getMedia();
            Media media = mediaService.getMediaById(mediaId);
            if (dbMedia != null) {
                if (!mediaId.equals(dbMedia.getMediaId())) {
                    customer.setMedia(media);
                }
            } else {
                customer.setMedia(media);
            }
        }
        if (StringUtils.isNotEmpty(model.getSex())) {
            customer.setCustomerGender(model.getSex());
        }
        if (StringUtils.isNotEmpty(model.getNickname())) {
            customer.setCustomerNickname(model.getNickname());
        }
        if (StringUtils.isNotEmpty(model.getName())) {
            customer.setCustomerLastname(model.getName());
        }
        return customerRepository.save(customer);
    }

    /**
     * 绑定会员卡
     *
     * @param customer
     * @param targetNum
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public void bindLoyaltyCard(Customer customer, String targetNum) {
        Assert.hasText(targetNum, "绑定的会员卡号不能为空");
        //原会员卡与目标会员卡一致则直接返回
        if (targetNum.equalsIgnoreCase(customer.getLoyaltyCard())) {
            return;
        }
        if (StringUtils.isNotBlank(customer.getLoyaltyCard())) {
            CustomerCardHistory sourceHistory = customerCardHistoryRepository.findFirstByOpenidAndCardNumber(customer.getOpenId(), customer.getLoyaltyCard());
            if (sourceHistory == null) {
                sourceHistory = customerCardHistoryRepository.findFirstByMerchantIdAndCardNumber(customer.getMerchantStore().getMerchantId(), customer.getLoyaltyCard());
            }
            if (sourceHistory == null) {
                sourceHistory = new CustomerCardHistory();
                sourceHistory.setCardNumber(customer.getLoyaltyCard());
                sourceHistory.setOpenid(customer.getOpenId());
                sourceHistory.setMerchantId(customer.getMerchantStore().getMerchantId());
                sourceHistory.setUnionId(customer.getUnionId());
                sourceHistory.setTelephone(customer.getCustomerPhone());
            }
            BigInteger points = customer.getBonusPoints();
            sourceHistory.setBonusPonits(points == null ? BigInteger.ZERO : points);
            customerCardHistoryRepository.save(sourceHistory);
        }
        if (StringUtils.isNotBlank(targetNum)) {
            /***
             * 查询原有记录中是否有该卡的记录
             * 1、先按照openid和会员卡查
             * 2、再按照门店和会员卡号查
             * 2、最后按照门店和电话号码查
             * */
            CustomerCardHistory targetHistory = null;
            if (StringUtils.isNotBlank(customer.getOpenId())) {
                targetHistory = customerCardHistoryRepository.findFirstByOpenidAndCardNumber(customer.getOpenId(), targetNum);

            }
            if (targetHistory == null) {
                targetHistory = customerCardHistoryRepository.findFirstByMerchantIdAndCardNumber(customer.getMerchantStore().getMerchantId(), targetNum);
            }
            /*if (targetHistory == null) {
                targetHistory = customerCardHistoryRepository.findFirstByMerchantIdAndTelephone(customer.getMerchantStore().getMerchantId(), customer.getCustomerPhone());
            }*/
            if (targetHistory != null) {
                //有记录将找回原记录中的积分
                BigInteger pointsHistory = targetHistory.getBonusPonits();
                customerRepository.updateBonusPoints(customer.getCustomerId(),pointsHistory == null ? BigInteger.ZERO : pointsHistory);
            } else {
                /*targetHistory = new CustomerCardHistory();
                targetHistory.setCardNumber(customer.getLoyaltyCard());
                targetHistory.setOpenid(customer.getOpenId());
                targetHistory.setMerchantId(customer.getMerchantStore().getMerchantId());
                targetHistory.setUnionId(customer.getUnionId());
                targetHistory.setTelephone(customer.getCustomerPhone());
                customerCardHistoryRepository.save(targetHistory);*/
                //没有记录则设置会员积分为0
                //customer.setBonusPoints(BigInteger.ZERO);
            }
            customer.setLoyaltyCard(targetNum);
            customer.setUpdatedTimestamp(new Date());
            //会员重新绑定、恢复同步标识。门店会员信息重新同步到中间库
            if(Boolean.TRUE.equals(customer.getSync()))
                customer.setSync(Boolean.FALSE);
            customerRepository.save(customer);
        }
    }

    /**
     * 奖励会员积分
     *
     * @param order
     * @param loyaltyNo
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public void rewardsBonusPoints(Order order, String loyaltyNo) {
        //已经处理过该订单
        if (bonusPointsService.findProcessedHistory(order.getOrderNumber(), loyaltyNo, BonusPointsUpdatedType.INCREMENT) != null) {
            return;
        }
        List<OrderItem> items = order.getOrderItems();
        Customer customer = order.getCustomer();
        Integer totalBonusPoints = 0;
        for (OrderItem item : items) {
            Long sku = item.getSkuId();
            Boolean promoApplied = item.isPromoApplied();
            Map map = bonusPointsService.getBonusPointsRatio(sku, customer, promoApplied);
            Integer bonusPointsRate = (Integer) map.get("ratio");
            BigDecimal times = (BigDecimal) map.get("times");
            if (bonusPointsRate != null && bonusPointsRate.compareTo(0) > 0) {
                //计算顺序：单个商品价格乘以积分倍率除以积分率得到单商品的积分值最后乘以数量得到行项目的积分值
                Integer points = item.getSkuPrice().multiply(times == null ? BigDecimal.ONE : times).divide(BigDecimal.valueOf(bonusPointsRate), 2, BigDecimal.ROUND_HALF_UP).setScale(0, BigDecimal.ROUND_HALF_UP).multiply(BigDecimal.valueOf(item.getSkuQuantity())).intValue();
                item.setBonusPoints(points);
                totalBonusPoints += points;
            } else {
                item.setBonusPoints(0);
            }
        }
        order.setTotalBonusPoints(BigInteger.valueOf(totalBonusPoints));
        orderService.save(order);
        bonusPointsService.incrementBonusPoints(customer, order.getOrderNumber(), BigInteger.valueOf(totalBonusPoints), BonusPointsSource.MALL, BonusPointsUpdatedDetail.ORDER, String.format("商城订单：%d", order.getOrderId()));
    }

    /**
     * 回滚订单奖励的积分
     *
     * @param order
     * @param loyaltyNo
     * @throws BonusPointsNotEnoughException
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public void rollbackBounsPoints(Order order, String loyaltyNo) throws BonusPointsNotEnoughException {
        //已经处理过该订单
        if (bonusPointsService.findProcessedHistory(order.getOrderNumber(), loyaltyNo, BonusPointsUpdatedType.DECREMENT) != null) {
            return;
        }
        BigInteger bonuspoints = order.getTotalBonusPoints();

        if (bonuspoints != null && bonuspoints.compareTo(BigInteger.ZERO) > 0) {
            Customer customer = order.getCustomer();
            bonusPointsService.decrementBonusPoints(customer, order.getOrderNumber(), order.getOrderNumber(), bonuspoints, BonusPointsSource.MALL, BonusPointsUpdatedDetail.ORDER, String.format("取消订单：%d", order.getOrderId()));
        }
    }

    /**
     * 退货订单退回相应奖励的积分
     *
     * @param orderReturn
     * @param loyaltyNo
     * @throws BonusPointsNotEnoughException
     */
    @Override
    @Transactional
    public void rollbackBounsPoints(OrderReturn orderReturn, String loyaltyNo) throws RollbackBonuspointsException, BonusPointsNotEnoughException {
        //查询该退货订单的退换积分操作是否已经进行过
        if (bonusPointsService.findProcessedHistory(orderReturn.getReturnNumber(), loyaltyNo, BonusPointsUpdatedType.DECREMENT) != null) {
            return;
        }
        BigInteger decrementBonusValue = getDecrementBonusValue(orderReturn);//获取退换订单需要减少积分

        //指定退回积分相关操作
        if (decrementBonusValue != null && decrementBonusValue.compareTo(BigInteger.ZERO) > 0) {
            orderReturnRepository.save(orderReturn);//保存退货行项目的积分
            Customer customer = orderReturn.getCustomer();
            String orderNumber = orderReturn.getReturnNumber();
            String originNumber = orderReturn.getRelatedOrder().getOrderNumber();
            bonusPointsService.decrementBonusPoints(customer, orderNumber, originNumber, decrementBonusValue, BonusPointsSource.MALL, BonusPointsUpdatedDetail.ORDER_REFUND, String.format("退货：%d", orderReturn.getId()));
        }

    }

    private BigInteger getDecrementBonusValue(OrderReturn orderReturn) throws RollbackBonuspointsException {
        List<OrderReturnItem> returnItems = orderReturn.getOrderReturnItems();
        List<OrderItem> orderItems = orderReturn.getRelatedOrder().getOrderItems();
        checkValid(returnItems, orderItems);//校验退货条目是否包含在原单条目中，并且数量必须小于原单条目
        Map<Long, Integer> unitBonus = getUnitBonus(orderItems);//获取单个item的积分
        Integer decrementBonusValue = 0;
        if (CollectionUtils.isNotEmpty(returnItems)) {
            for (OrderReturnItem orderReturnItem : returnItems) {
                Integer itemBonus = unitBonus.get(orderReturnItem.getSkuId()) * orderReturnItem.getSkuQuantity();
                orderReturnItem.setBonusPoints(itemBonus);//保存退货行项目的积分
                decrementBonusValue += itemBonus;
            }
        }
        return new BigInteger(decrementBonusValue.toString());
    }

    /**
     * 获取单个item的积分
     *
     * @param orderItems 原单行项目
     * @return
     */
    private Map<Long, Integer> getUnitBonus(List<OrderItem> orderItems) {
        Map<Long, Integer> unitBonusMap = new HashMap<>();
        for (OrderItem orderItem : orderItems) {
            Integer unitBonus = orderItem.getBonusPoints() / orderItem.getSkuQuantity();
            unitBonusMap.put(orderItem.getSkuId(), unitBonus);
        }
        return unitBonusMap;
    }

    /**
     * /校验退货条目是否包含在原单条目中，并且数量必须小于原单条目
     *
     * @param returnItems 退当行项目
     * @param orderItems  原当行项目
     */
    private void checkValid(List<OrderReturnItem> returnItems, List<OrderItem> orderItems) throws RollbackBonuspointsException {
        //TODO
        Map<Long, Integer> map = new HashMap<>();
        for (OrderItem orderItem : orderItems) {
            map.put(orderItem.getSkuId(), orderItem.getSkuQuantity());
        }
        for (OrderReturnItem orderReturnItem : returnItems) {
            Integer quantity = map.get(orderReturnItem.getSkuId());
            if (null == quantity)
                throw new RollbackBonuspointsException("原单中不存在该退货行项目：" + orderReturnItem.getSkuName());
            if (orderReturnItem.getSkuQuantity() > quantity)
                throw new RollbackBonuspointsException("退货行项目："
                        + orderReturnItem.getSkuName()
                        + " 数量："
                        + orderReturnItem.getSkuQuantity()
                        + " 大于原单行项目数量:"
                        + quantity);
        }
    }

    /**
     * 根据门店获取默认会员
     *
     * @param storeId
     * @return
     */
    @Override
    public CustomerType findDefaultCustomerType(Long storeId) {
        return customerTypeRepository.findFirstByTypeCodeAndMerchantId(CustomerType.DEFAULT_TYPE_CODE, storeId);
    }

    /**
     * 查询门店会员卡对应的会员
     *
     * @param store
     * @param cardNumber
     * @return
     */
    @Override
    public Customer findCustomer(MerchantStore store, String cardNumber) {
        return null;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean register(Customer user, String name, String mobile, String idNum, String verifyCode, int publicid, int ppid, Long stroeId, String userId) {

        boolean result = Boolean.TRUE;
        String unionid = user.getUnionId();
        String method = "CreateCard";
        JSONObject json = memberService.register(method, unionid, name, mobile, idNum, verifyCode, publicid, ppid);
        //测试返回数据
        //JSONObject json = JSONObject.parseObject("{\"ret\":0,\"errmsg\":\"成功返回\"}");
        log.info(String.format("unionId:{%s} ，idNum:{%s}  注册crm会员返回信息:%s",unionid,idNum, json));
        //if(json.containsKey("ret") && json.getString("ret").equalsIgnoreCase("0")){
        if (json.containsKey("ret") && json.getIntValue("ret") == 0) {
            //在福基注册会员成功
            MerchantStore merchantStore = null;
            if (stroeId!=null) {
                merchantStore = merchantStoreRepository.findOne(stroeId);//修改本地会员门店
                user.setMerchantStore(merchantStore);
            }
            if(checkFirstRegister(user,mobile)){
                //注册赠送积分和推荐赠送积分 --------start-----------
                String remark = "用户注册成功赠送积分";
                List<MerchantConfiguration> configurationList = configurationRepository.findByMerchantStoreAndType(stroeId, MerchantConfigurationType.REGISTER_RELATED_BONUSPOINTS);
                String addPointsValue="0";
                if(!configurationList.isEmpty()){
                    MerchantConfiguration register = configurationList.stream().filter(merchantConfiguration -> {
                        return merchantConfiguration.getKey().equalsIgnoreCase("REGISTER");
                    }).findFirst().orElse(null);
                    if(register!=null){ addPointsValue=register.getValue();}
                }
                bonusPointsService.addBonusPoints(user, addPointsValue, remark, BonusPointsUpdatedDetail.REGISTER_CUSTOMER);
                log.info(String.format("用户:%s,注册成功增加积分:%s", user.getCustomerLastname(), addPointsValue));
                // 微信模板消息发送
                applicationContext.publishEvent(new CustomerRegisterEvent(this,user.getCustomerId(),addPointsValue));

                //用户注册是受别人推荐
                if (StringUtils.isNotBlank(userId)) {
                    remark = String.format("推荐会员：%s 注册成功赠送积分", user.getCustomerLastname());
                    if(!configurationList.isEmpty()){
                        MerchantConfiguration invitationRegister = configurationList.stream().filter(merchantConfiguration -> {
                            return merchantConfiguration.getKey().equalsIgnoreCase("INVITATION_REGISTER");
                        }).findFirst().orElse(null);
                        if(invitationRegister!=null){ addPointsValue=invitationRegister.getValue();}
                    }
                    //推荐人
                    Customer referrer = customerRepository.findOne(Long.valueOf(userId));
                    Assert.notNull(referrer, "推荐人卡号有误");
                    bonusPointsService.addBonusPoints(referrer, addPointsValue, remark, BonusPointsUpdatedDetail.INVITATION_REGISTER);
                    referrer = findCustomer(referrer.getCustomerId());
                    log.info(String.format("用户:%s 推荐他人注册成功增加积分:%s", referrer.getCustomerLastname(), addPointsValue));
                    applicationContext.publishEvent(new CustomerRegisterEvent(this,user.getCustomerId(),addPointsValue));
                }
                //注册赠送积分和推荐赠送积分 --------end-----------
            }
            return result;
        } else {
            log.error("unionId:{} ，idNum:{}  会员注册失败，失败原因：{}",unionid,idNum,json.getString("errmsg"));
            throw new RuntimeException("crm注册会员失败");
        }
    }

    /**
     * 验证是否是第一次注册会员
     * @param user 用户
     * @param mobile 电话
     * @return
     */
    private boolean checkFirstRegister(Customer user, String mobile) {
        if(StringUtils.isNotBlank(user.getLoyaltyCard())){
            return false;
        }

        Customer customer = customerRepository.
                findFirstByCustomerPhoneAndLoyaltyCardIsNotNull(mobile);
        if(null != customer){
            return false;
        }

        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public BigInteger signIn(Customer customer, Long storeoId, String remark) {

        if(StringUtils.isNotBlank(redis.boundValueOps(String.format("dailySignIn:%s", customer.getOpenId())).get())){
            throw new KnownRuntimeException("您已经进行签到过啦！");
        }

        // 查询门店签到积分配置  依照持续天数  从大到小排序
        List<MerchantConfiguration> configurations = configurationRepository.findByMerchantStoreAndTypeDesc(storeoId, MerchantConfigurationType.DAILY_SIGN_IN);
        Assert.notEmpty(configurations,"商城还未提供签到功能！");

        //最后一次签到记录
        DailySignInHistory lastSignIn = signInHistoryRepository.findFirstByCustomerOrderBySignInDateDesc(customer);

        //根据持续签到获取积分
        Map<String,Object> pointsMap = signInBonusPoints(lastSignIn, configurations);

        DailySignInHistory history = new DailySignInHistory();

        //添加连续签到记录
        history.setPersistenceSignInDays(Integer.parseInt(String.valueOf(pointsMap.get("persistenceSignIn"))));

        //增加积分
        Long historyId = null;
        if(BigInteger.ZERO.compareTo((BigInteger)pointsMap.get("bonusPoints")) != 0) {
            historyId = bonusPointsService.incrementBonusPoints(customer, null, (BigInteger) pointsMap.get("bonusPoints"), BonusPointsSource.MALL, BonusPointsUpdatedDetail.DAILY_SIGN_IN,
                    String.format("会员：%s ，完成每日签到，连续签到%s日，增加%s积分",
                            customer.getCustomerNickname(), pointsMap.get("persistenceSignIn"),
                            (BigInteger) pointsMap.get("bonusPoints")));
        }

        //积分历史ID
        history.setBonusPointsHistoryId(historyId);
        //签到备注（心情）
        history.setRemark(remark);
        // 签到时间 -- 可用于补签 （实际补签时间）
        history.setSignInDate(new Date());
        //最后一次签到时间  --当前时间
        history.setSignInLastDate(new Date());
        history.setCustomer(customer);
        history = signInHistoryRepository.save(history);

        //保存签到标识
        redis.boundValueOps(String.format("dailySignIn:%s", customer.getOpenId())).set("1", DateUtils.getReaminSecondsToday(), TimeUnit.SECONDS);
        redis.boundValueOps(String.format("persistenceSignIn:%s", customer.getOpenId())).set((String)pointsMap.get("persistenceSignIn"));


        return  (BigInteger)pointsMap.get("bonusPoints");
    }

    @Override
    public List signInDetail(Customer customer) {
        Date firstDayOfMonth = DateUtils.getFirstDayOfMonth(new Date());
        List<DailySignInHistory> signs = signInHistoryRepository.findByCustomerAndMonth(customer.getCustomerId(),firstDayOfMonth);
        Assert.notNull(signs,"您本月还未进行签到");
        ArrayList<Map> resultList = new ArrayList<>(signs.size());
        signs.forEach(dailySignInHistory -> {
            HashMap<String, Object> map = new HashMap<>();
            map.put("remark",dailySignInHistory.getRemark());
            map.put("signInDate",dailySignInHistory.getSignInDate());
            resultList.add(map);
        });

        return resultList;
    }

    private Map signInBonusPoints(DailySignInHistory lastSignIn, List<MerchantConfiguration> configurations) {

        HashMap<String, Object> result = new HashMap<>(2);
        // 拿到首日积分
        MerchantConfiguration firstDayConfiguration = configurations.get(configurations.size()-1);
        String firstDayBonusPoints = "0";
        if(firstDayConfiguration!=null&&firstDayConfiguration.getKey().equalsIgnoreCase("1")) {
            firstDayBonusPoints = firstDayConfiguration.getValue();
        }

        // 第一次签到 / 间断签到
        if(lastSignIn==null|| !LocalDate.now().minusDays(1).isEqual(LocalDateUtils.fromDate(lastSignIn.getSignInDate()))){
            result.put("persistenceSignIn","1");
            result.put("bonusPoints",new BigInteger(firstDayBonusPoints));
            return result;
        }


        for (int i = 0; i < configurations.size(); i++) {
            MerchantConfiguration configuration = configurations.get(i);
            Integer signInDays = lastSignIn.getPersistenceSignInDays();

            // 签到天数达到最大持续天数 重置
            if(i==0&&(signInDays+1)>Integer.valueOf(configuration.getKey())){
                result.put("persistenceSignIn","1");
                //得到首日日签到积分数
                result.put("bonusPoints",new BigInteger(firstDayBonusPoints));
                return result;

            //比较持续天数  返回签到积分
            }else if((signInDays+1)==Integer.valueOf(configuration.getKey())){
                // 没有超过 直接返回累计数
                result.put("bonusPoints",new BigInteger(configuration.getValue()));
                result.put("persistenceSignIn",(signInDays+1)+"");
                return result;

                //没有比较到持续天数  返回首日签到积分
            }else if(configurations.size()-1 == i){
                result.put("bonusPoints",new BigInteger(firstDayBonusPoints));
                result.put("persistenceSignIn",(signInDays+1)+"");
                return result;
            }
        }
        return null;
    }

    @Override
    public ResultModel getLoyaltyInfo(Long userId) {
        Customer user = findCustomer(userId);
        String unionid = user.getUnionId();
        JSONObject json = memberService.getMemberInfo(unionid);
        if(json.containsKey("errCode")&&json.getIntValue("errCode")==0){
            if (JSONPath.contains(json,"$.data.cardno")) {
                String cardNo =(String) JSONPath.eval(json,"$.data.cardno");
                if (!cardNo.equals(user.getLoyaltyCard()) && StringUtils.isNotBlank(cardNo)) {
                    if(JSONPath.contains(json,"$.data.username")){
                        user.setCustomerLastname(""+JSONPath.eval(json,"$.data.username"));
                    }
                    if(JSONPath.contains(json,"$.data.tel")){
                        user.setCustomerPhone(""+JSONPath.eval(json,"$.data.tel"));
                    }
                    bindLoyaltyCard(user,cardNo);
                }
                int count = couponService.countCoupons(user);
                CustomerType type = user.getCustomerType();
                if(type==null){
                    type = findDefaultCustomerType(user.getMerchantStore().getMerchantId());
                }
                return ResultModel.ok().put("bonusPoints",user.getBonusPoints())
                        .put("avatar",user.getMedia()==null?"":user.getMedia().getUrl())
                        .put("loyaltyNumber",cardNo)
                        .put("couponQuantity",count)
                        .put("customerName",user.getCustomerLastname())
                        .put("storeName",user.getMerchantStore().getStoreName())
                        .put("background",type==null?null:type.getBackground())
                        .put("logo",type==null?null:type.getLogo())
                        .put("other",type==null?null:type.getConfig());
            }
        }
        log.warn(unionid+":"+json.getString("errMessage"));
        return ResultModel.error("请绑定会员卡");
    }

    @Override
    //@CacheEvict(value = "LoyaltyInfo",key = "#userId")
    public ResultModel bind(Long userId, String mobile, String idNum, String verifyCode, String cardno, int publicid, int ppid) {
        Customer user = findCustomer(userId);
        String unionid = user.getUnionId();
        String method ="BindCard";
        JSONObject json = memberService.bind(method,unionid,mobile,idNum,verifyCode,cardno,publicid,ppid);
        if(json.containsKey("ret") && json.getIntValue("ret")==0){
            user.setIdentificationId(idNum);
            saveCustomer(user);
            return ResultModel.ok(json.getString("errmsg"));
        }
        return ResultModel.error(json.getString("errmsg"));
    }
}
